package com.v9.main.controller.flow;


import com.v9.common.dto.PageInfoDto;
import com.v9.common.dto.UserDto;
import com.v9.common.web.AbstractController;
import com.v9.flow.FlowEventHandler;
import com.v9.flow.domain.FlowBizType;
import com.v9.flow.domain.FlowInfo;
import com.v9.flow.service.FlowBizTypeService;
import com.v9.flow.service.FlowInfoService;
import com.v9.system.domain.DeptInfo;
import com.v9.system.domain.RoleInfo;
import com.v9.system.service.DeptInfoService;
import com.v9.system.service.RoleInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FormProperty;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author lunshi
 */
@RestController
@Tag(name = "工作流任务")
@RequestMapping(
        value = {"/fl/task"},
        method = {RequestMethod.POST}
)
@Slf4j
public class TaskController extends AbstractController implements ApplicationContextAware {


    @Autowired
    private TaskRuntime taskRuntime;
    @Resource
    private TaskService taskService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ProcessEngine processEngine;
    @Resource
    private RuntimeService runtimeService;
    @Autowired
    private ProcessRuntime processRuntime;
    @Resource
    private FlowInfoService flowInfoService;
    @Resource
    private FlowBizTypeService flowBizTypeService;
    private String[] beanNamesForType;
    private Map<String, FlowEventHandler> flowMapping = new HashMap<>();
    private ApplicationContext applicationContext;

    @Resource
    private RoleInfoService roleInfoService;
    @Resource
    private DeptInfoService deptInfoService;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 启动任务
     *
     * @param code     流程key
     * @param formData 表单数据json
     */
    @RequestMapping({"instance/{code}"})
    @Operation(summary = "实例化")
    public void instance(@PathVariable String code, @RequestBody Map<String, Object> formData) {
        formData.forEach((k,v)->{

        });
        UserDto user = getUser();
        if (beanNamesForType == null) {
            beanNamesForType = applicationContext.getBeanNamesForType(FlowEventHandler.class);
            for (String beanName : beanNamesForType) {
                FlowEventHandler bean = (FlowEventHandler) applicationContext.getBean(beanName);
                flowMapping.put(bean.getCode(), bean);
            }
        }
        FlowEventHandler handler = flowMapping.get(code);
        if (handler != null) {
            handler.handle(null,null,formData);
        }
        flowInfoService.instance(code, user, formData);
    }

    @RequestMapping({"instance/{code}/{instanceId}"})
    @Operation(summary = "实例化")
    public String viewTask(@PathVariable String code, @PathVariable String instanceId) {
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(code);
        List<HistoricTaskInstance> list = processEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(instanceId).list();
        list.forEach(item -> {
            //颜色改变
        });
        BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
        byte[] convertToXML = bpmnXMLConverter.convertToXML(bpmnModel);
        return new String(convertToXML);
    }

    /**
     * 任务查询
     *
     * @param
     */
    @RequestMapping({"list"})
    @Operation(summary = "查询个人任务")
    public Page<FlowTaskDto> listActiveTask(@RequestBody PageInfoDto dto) {
       UserDto user=getUser();
//        创建TaskService
        TaskService taskService = processEngine.getTaskService();
//        根据流程key 和 任务负责人 查询任务
        TaskQuery taskQuery = taskService.createTaskQuery();

        long count = taskQuery.active().taskCandidateOrAssigned(user.getPin(), user.getFlowGroup()).count();
        List<Task> tasks = taskQuery.active().taskCandidateOrAssigned(user.getPin(), user.getFlowGroup()).listPage(dto.getPage() * dto.getSize(), dto.getSize());
        List<FlowTaskDto> result = new ArrayList();
        for (Task task : tasks) {
            List<ProcessInstance> instanceList = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).list();
            Long detailTypeId = Long.parseLong(instanceList.get(0).getProcessDefinitionId());
            UserTask userTask = (UserTask) repositoryService.getBpmnModel(detailTypeId.toString()).getFlowElement(task.getFormKey());
            List<FormProperty> formProperties = userTask.getFormProperties();

            FlowTaskDto taskDto = new FlowTaskDto();
            taskDto.setFromData(new ArrayList<>());
            formProperties.forEach((item) -> {
                FormItemDto itemDto = new FormItemDto();
                itemDto.setName(item.getName());
                itemDto.setType(item.getType());
                itemDto.setRequired(item.isRequired());
                taskDto.getFromData().add(itemDto);
            });
            String formKey1 = task.getFormKey();
            taskDto.setTaskName(task.getName());
            taskDto.setInstanceId(task.getProcessInstanceId());
            ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId());
            //业务流转变量（关键性数据）
            Map<String, Object> processVariables = instanceList.get(0).getProcessVariables();
            List<ProcessInstance> list = processInstanceQuery.list();
            String title = (String) list.get(0).getProcessVariables().get("title");
            taskDto.setTitle(title);
            String formKey = formKey1;
            //TODO  .....
        }
        return new PageImpl(result, dto.getPageable(), count);
    }

    /**
     * 任务处理
     *
     * @param
     */
    @RequestMapping({"complete/{taskId}"})
    @Operation(summary = "处理流程")
    public void complete(@PathVariable String taskId, @RequestBody Map<String, Object> formData) {
        UserDto user=getUser();
        if (beanNamesForType == null) {
            beanNamesForType = applicationContext.getBeanNamesForType(FlowEventHandler.class);
            for (String beanName : beanNamesForType) {
                FlowEventHandler bean = (FlowEventHandler) applicationContext.getBean(beanName);
                flowMapping.put(bean.getCode(), bean);
            }
        }
        Task task = taskService.createTaskQuery().taskId(taskId).list().get(0);
        String processDefinitionId = task.getProcessDefinitionId();
        processDefinitionId = processDefinitionId.substring(0, processDefinitionId.indexOf(":"));
        FlowEventHandler handler = flowMapping.get(processDefinitionId);
        //验证处理表单
        if (handler != null) {
            handler.handle(task.getProcessInstanceId(),task.getTaskDefinitionKey(),formData);
        }
        taskService.claim(taskId, user.getUsername());
        taskService.complete(taskId, formData);
    }

    @RequestMapping({"taskHis"})
    @Operation(summary = "流程历史")
    public Page<FlowTaskDto> taskHis(@RequestBody FLowTaskHisQuery dto) {
        UserDto user=getUser();
        HistoricTaskInstanceQuery historicTaskInstanceQuery = processEngine.getHistoryService().createHistoricTaskInstanceQuery().taskAssignee(user.getUsername());
        if (dto.getDetailTypes() != null) {
            List<String> keys = new ArrayList<>();
            dto.getDetailTypes().forEach(item -> {
                keys.add(item);
            });
            historicTaskInstanceQuery.processDefinitionKeyIn(keys);
        }

        long count = historicTaskInstanceQuery.count();
        List<HistoricTaskInstance> tasks = historicTaskInstanceQuery.listPage(dto.getSize() * dto.getPage(), dto.getSize());
        List<FlowTaskDto> result = new ArrayList();
        for (HistoricTaskInstance task : tasks) {
            FlowTaskDto item = new FlowTaskDto();
            String instanceId = item.getInstanceId();
            List<HistoricProcessInstance> list = processEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(instanceId).list();
            Long flowId = Long.parseLong(list.get(0).getProcessDefinitionKey());
            FlowInfo info = flowInfoService.findById(flowId);
            FlowBizType bizType = flowBizTypeService.findById(info.getBizTypeId());
            item.setFlowBizTypeName(bizType.getName());
            String createByUserId = (String) task.getProcessVariables().get("createByUserId");
            String createByUserName = (String) task.getProcessVariables().get("createByUserName");
            item.setCreateByUserId(createByUserId);
            item.setCreateByTime((Date) task.getProcessVariables().get("createByTime"));
            item.setTitle((String) task.getProcessVariables().get("title"));
            item.setTaskName(createByUserName);
            item.setTaskName(task.getName());
            item.setTaskId(task.getParentTaskId());
            item.setCreateTime(task.getCreateTime());
            item.setClaimTime(task.getClaimTime());
            item.setEndTime(task.getEndTime());
            result.add(item);
        }
        return new PageImpl(result, dto.getPageable(), count);
    }

    @Data
    public static class FLowTaskHisQuery extends PageInfoDto {
        @Schema(description = "流程分类id")
        private List<String> detailTypes;
    }

    @Data
    public static class FlowDefineDto {
        private String key;
        private String name;
        private int version;
    }

    @Data
    public static class FlowTaskDto {
        @Schema(description = "创建人Id")
        private String createByUserId;
        @Schema(description = "创建人名称")
        private String createByUserName;
        @Schema(description = "流程创建时间")
        private Date createByTime;
        @Schema(description = "任务key")
        private String taskKey;
        @Schema(description = "任务名称")
        private String taskName;
        @Schema(description = "任务id")
        private String taskId;
        @Schema(description = "流程实例id")
        private String instanceId;
        private String flowBizTypeName;
        @Schema(description = "title")
        private String title;
        @Schema(description = "任务创建时间")
        private Date createTime;
        @Schema(description = "任务开始时间")
        private Date claimTime;
        @Schema(description = "任务完成时间")
        private Date endTime;
        private List<FormItemDto> fromData;
    }


    @Data
    public static class FormItemDto {
        @Schema(description = "表单数据类型")
        private String type;
        @Schema(description = "表单属性名称")
        private String name;
        @Schema(description = "是否必填")
        private Boolean required;
    }

    @Data
    public static class CaseInfoDto {
        private String source;
        private String name;
    }
}
